package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.constant.JiGuangConstant;
import com.csun.cmny.base.dto.LoginAuthDto;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.provider.constant.Constant;
import com.csun.cmny.provider.dao.*;
import com.csun.cmny.provider.dto.OmcOldLeaveQueryDto;
import com.csun.cmny.provider.exceptions.OmcBizException;
import com.csun.cmny.provider.model.constant.MedicConstant;
import com.csun.cmny.provider.model.constant.OldOutConstant;
import com.csun.cmny.provider.model.constant.ReviseConstant;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.SendMessageRequest;
import com.csun.cmny.provider.model.dto.revise.*;
import com.csun.cmny.provider.model.enums.UacRoleCodeEnum;
import com.csun.cmny.provider.model.vo.OldmanBedRoomBuildingVo;
import com.csun.cmny.provider.model.vo.RpcRoleVo;
import com.csun.cmny.provider.model.vo.revise.*;
import com.csun.cmny.provider.pojo.Bed;
import com.csun.cmny.provider.pojo.NursingGroup;
import com.csun.cmny.provider.pojo.Oldman;
import com.csun.cmny.provider.pojo.Room;
import com.csun.cmny.provider.resolver.CmnyMessageSource;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.vo.BedNosVo;
import com.csun.cmny.provider.vo.BedVo;
import com.csun.cmny.provider.vo.MyCommentVo;
import com.csun.cmny.provider.vo.OmcAdjustRefundData;
import com.csun.cmny.util.DateUtil;
import com.csun.cmny.util.PublicUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jline.internal.Log;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2019-09-09 16:49
 * @Description: the class omc revise service impl
 */
@Slf4j
@Service
@Transactional
public class OmcReviseServiceImpl extends BaseService<OmcRevise> implements OmcReviseService {

    @Resource
    private OmcReviseMapper omcReviseMapper;
    @Resource
    private OmcCycleExpenseItemMapper omcCycleExpenseItemMapper;
    @Resource
    private OmcExpenseTypeModelCodeMapper omcExpenseTypeModelCodeMapper;
    @Resource
    private OmcActivitiService omcActivitiService;
    @Resource
    private TaskService taskService;
    @Resource
    private OmcReviseVarService omcReviseVarService;
    @Resource
    private UacRpcService uacRpcService;
    @Resource
    private OmcOldManSupplementMapper omcOldManSupplementMapper;
    @Resource
    private OmcOldManTypeIetypeMapper omcOldManTypeIetypeMapper;
    @Resource
    private OmcOldManBillService omcOldManBillService;
    @Resource
    private OmcBillMealService omcBillMealService;
    @Resource
    private OmcReturnFeeConfigService omcReturnFeeConfigService;
    @Resource
    private OmcReviseItemService omcReviseItemService;
    @Resource
    private OmcReviseSetMealService omcReviseSetMealService;
    @Resource
    private OmcReviseSetMealItemService omcReviseSetMealItemService;
    @Resource
    private OmcGroupService omcGroupService;
    @Resource
    private OmcNursingRoomBindMapper omcNursingRoomBindMapper;
    @Resource
    private OmcReviseBedService omcReviseBedService;
    @Resource
    private OldmanService oldmanService;
    @Resource
    private BedService bedService;
    @Resource
    private OmcBillAdjustFeeMapper omcBillAdjustFeeMapper;
    @Resource
    private OmcBillItemService omcBillItemService;
    @Resource
    private OmcBillSetMealItemService omcBillSetMealItemService;
    @Resource
    private OmcOldManAccountFundsService omcOldManAccountFundsService;
    @Resource
    private OmcCycleExpenseItemService omcCycleExpenseItemService;
    @Resource
    private OmcExpenseTypeModelCodeService omcExpenseTypeModelCodeService;
    @Resource
    private OmcOldmanStatusService omcOldmanStatusService;
    @Resource
    private OmcOldLeaveService omcOldLeaveService;
    @Resource
    private OpcMessageService opcMessageService;
    @Resource
    private OmcOldManSupplementService supplementService;
    @Resource
    private RoomService roomService;


    /**
     * query revise oldman list
     *
     * @param reviseOldmanQueryDto the revise oldman query dto
     * @return the revise oldman vo
     */
    @Override
    public List<ReviseOldmanVo> queryOldmanList(ReviseOldmanQueryDto reviseOldmanQueryDto) {

        List<Integer> statusList = Lists.newArrayList();
        statusList.add(Constant.YIRUYUAN);
        statusList.add(Constant.SHIRUZHU);
        reviseOldmanQueryDto.setOldmanStateList(statusList);

        List<Integer> stateList = Lists.newArrayList();
        stateList.add(ReviseConstant.REVISE_STATE_SERVICE_REFUSE);
        stateList.add(ReviseConstant.REVISE_STATE_CHARGE_CONFIRM);
        reviseOldmanQueryDto.setReviseStateList(stateList);

        return omcReviseMapper.queryOldmanList(reviseOldmanQueryDto);
    }

    /**
     * query revise oldman fee by oldman id
     *
     * @param oldmanId      the oldman id
     * @param loginAuthDto  the login auth dto
     *
     * @return the oldman fee vo
     */
    @Override
    public OldmanFeeVo queryByOldmanId(Integer oldmanId, LoginAuthDto loginAuthDto, String reviseDate) {

        OldmanFeeVo oldmanFeeVo = new OldmanFeeVo();
        Long groupId = loginAuthDto.getGroupId();

        ReviseOldmanQueryDto reviseOldmanQueryDto = new ReviseOldmanQueryDto();
        reviseOldmanQueryDto.setGroupId(groupId);
        reviseOldmanQueryDto.setOldmanId(oldmanId);
        List<ReviseOldmanVo> reviseOldmanVoList = omcReviseMapper.queryOldmanList(reviseOldmanQueryDto);
        if (PublicUtil.isEmpty(reviseOldmanVoList)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038012);
        }

        String inDate = reviseOldmanVoList.get(0).getInDate();
        if (PublicUtil.isEmpty(inDate)) {   // 老人未入院
            throw new OmcBizException(ErrorCodeEnum.OMC10038036);
        }

        // 查询该老人的缴费信息
        Map<Long, OldmanPaymentFeeVo> oldmanPaymentFeeVoMap = Maps.newHashMap();
        GroupPaymentFeeQueryDto groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setIsAdjust(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST);
        groupPaymentFeeQueryDto.setOldmanId(oldmanId);
        List<OldmanPaymentFeeVo> oldmanPaymentFeeVoList = omcCycleExpenseItemMapper
                .queryOldmanPaymentFeeByOldmanId(groupPaymentFeeQueryDto);
        if (PublicUtil.isEmpty(oldmanPaymentFeeVoList)) {
            log.warn("老人无缴费信息");
            oldmanFeeVo.setOldmanPaymentFeeVo(null);
        } else {
            oldmanPaymentFeeVoMap = oldmanPaymentFeeVoList.stream()
                    .collect(Collectors.toMap(OldmanPaymentFeeVo::getExpenseItemId, item -> item));
        }
        oldmanFeeVo.setOldmanPaymentFeeVo(oldmanPaymentFeeVoList);

        // 查询老人--人员类别
        Long peopleType = omcOldManSupplementMapper.selectPeopleTypeByOldmanId(oldmanId);

        // 查询该机构的收费信息
        groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setGroupId(loginAuthDto.getGroupId());
        groupPaymentFeeQueryDto.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);
        groupPaymentFeeQueryDto.setIsAdjust(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST);
        List<GroupPaymentFeeVo> groupPaymentFeeVoList = omcExpenseTypeModelCodeService
                .queryGroupPaymentFeeByGroupId(groupPaymentFeeQueryDto);
        if (PublicUtil.isEmpty(groupPaymentFeeVoList)) {
            log.warn("机构无缴费信息");
            oldmanFeeVo.setGroupPaymentFeeVo(null);
        }

        // 如果无人员类型 则不需要查询人员类别减免
        if (PublicUtil.isNotEmpty(peopleType)) {
            for (GroupPaymentFeeVo gpfv : groupPaymentFeeVoList) {
                // 根据费用列表 - 人员类别查询
                OmcOldManTypeIetype omtit = new OmcOldManTypeIetype();
                omtit.setUserTypeId(peopleType);
                omtit.setItemId(gpfv.getExpenseTypeId());
                try {
                    omtit = omcOldManTypeIetypeMapper.selectOne(omtit);
                    if (PublicUtil.isNotEmpty(omtit)) {
                        gpfv.setPrecent(omtit.getPrecent());
                    }
                } catch (Exception e) {
                    throw new OmcBizException(ErrorCodeEnum.OMC10038013);
                }
            }
        }

        oldmanFeeVo.setGroupPaymentFeeVo(groupPaymentFeeVoList);

        // 查询老人最近一次的入院账单Id
        Long billId = omcOldManBillService.queryOldmanCheckInBillId(oldmanId);
        if (billId == null) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038012);
        }



        // 查询老人入院选择的套餐
//        List<OldmanSetMealVo> oldmanSetMealVoList = omcOldmanSetMealMapper
//                .queryOldmanSetMealByOldmanId(oldmanId);
        List<OldmanSetMealVo> oldmanSetMealVoList = omcBillMealService.queryOldmanSetMealByBillId(billId);
        if (PublicUtil.isEmpty(oldmanSetMealVoList)) {
            log.warn("老人未选中套餐");
            oldmanFeeVo.setOldmanSetMealVo(null);
        } else {
            // TODO 根据调整日期计算差额
            ReviseDaysVo reviseDaysVo = null;
            if (PublicUtil.isNotEmpty(reviseDate)) {
                ReviseDaysDto reviseDaysDto = new ReviseDaysDto();
                reviseDaysDto.setGroupId(groupId);
                reviseDaysDto.setReviseDate(DateUtil.stringToDate(reviseDate));
                reviseDaysDto.setCheckInDate(DateUtil.stringToDate(inDate));

                reviseDaysVo = omcReturnFeeConfigService.queryReviseDaysVo(reviseDaysDto);
                log.info("调整周期退费数 reviseDaysVo = {}", reviseDaysVo);
            }

            // 计算套餐剩余次数  -- 计算有问题
            if (PublicUtil.isNotEmpty(oldmanPaymentFeeVoMap)) {
                for (OldmanSetMealVo osmv : oldmanSetMealVoList) {
                    Iterator<OldmanSetMealItemVo> iterator = osmv.getOldmanSetMealItemVoList().iterator();
                    while (iterator.hasNext()) {
                        OldmanSetMealItemVo osmiv = iterator.next();
                        BigDecimal residueDegree = osmiv.getUsedDegree().add(osmiv.getResidueDegree());
                        if (PublicUtil.isEmpty(oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()))) {
                            // 套餐项目不在周期收费中，不进行退费
                            log.warn("套餐项目不在可调整周期收费中 ====》 ExpenseItemId =【{}】", osmiv.getExpenseItemId());
                            iterator.remove();
                        } else {
                            //osmiv.setResidueDegree(oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()).getResidueDegree());
                            // 剩余周期数 = 周期开始日期的套餐剩余周期数（usedDegree + residueDegree）
                            if (PublicUtil.isNotEmpty(reviseDaysVo)) {
                                // 剩余周期数为 = 调整账单周期开始日期的套餐剩余周期数 - 调整日期周期消费周期数
                                residueDegree = residueDegree.subtract(reviseDaysVo.getUsedPercent());
                            }
                        }
                        // 如果为负数，套餐以及使用完，剩余次数为0
                        if (residueDegree.compareTo(BigDecimal.ZERO) < 0) {
                            residueDegree = BigDecimal.ZERO;
                        }
                        osmiv.setResidueDegree(residueDegree); // 如果使用次数为0，说明当前周期之前套餐使用完成
                    }
//                    for (OldmanSetMealItemVo osmiv : osmv.getOldmanSetMealItemVoList()) {
//                        BigDecimal residueDegree = osmiv.getUsedDegree().add(osmiv.getResidueDegree());
//                        if (PublicUtil.isEmpty(oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()))) {
//                            // 套餐项目不在周期收费中，不进行退费
//                            log.warn("套餐项目不在可调整周期收费中 ====》 ExpenseItemId =【{}】", osmiv.getExpenseItemId());
//
//                        } else {
//                            //osmiv.setResidueDegree(oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()).getResidueDegree());
//                            // 剩余周期数 = 周期开始日期的套餐剩余周期数（usedDegree + residueDegree）
//                            if (PublicUtil.isNotEmpty(reviseDaysVo)) {
//                                // 剩余周期数为 = 调整账单周期开始日期的套餐剩余周期数 - 调整日期周期消费周期数
//                                // 如果为负数，套餐以及使用完，剩余次数为0
//                                residueDegree = residueDegree.subtract(reviseDaysVo.getUsedPercent());
//                            }
//                        }
//                        osmiv.setResidueDegree(residueDegree); // 如果使用次数为0，说明当前周期之前套餐使用完成
//                    }
                }
            }

            /**
             * 套餐剩余周期数计算公式：
             *
             *  如果套餐剩余次数不为0，则该周期内已经扣过一次，实际剩余周期数 = 1 +
             */
        }
        oldmanFeeVo.setOldmanSetMealVo(oldmanSetMealVoList);

        // 查询老人床位信息
        OldmanBedRoomBuildingVo oldmanBedRoomBuildingVo =
                oldmanService.queryOldmanBedRoomBuildingByOldmanId(oldmanId);
        if (oldmanBedRoomBuildingVo == null) {
            log.warn("老人无床位楼栋信息");
        }
        oldmanFeeVo.setOldmanBedRoomBuildingVo(oldmanBedRoomBuildingVo);

        return oldmanFeeVo;
    }

    /**
     * query revise vo list with page
     *
     * 不包含调房调级详情
     *
     * @param reviseQueryDto the revise query dto
     *
     * @return the revise vo list
     */
    @Override
    public List<ReviseVo> queryListWithPage(ReviseQueryDto reviseQueryDto) {

        return omcReviseMapper.queryListWithPage(reviseQueryDto);
    }

    /**
     * query revise vo by revise id
     *
     * @param id the revise id
     * @return the revise vo
     */
    @Override
    public ReviseVo queryById(Long id) {

        // 查询调房调级基本信息
        ReviseQueryDto reviseQueryDto = new ReviseQueryDto();
        reviseQueryDto.setReviseId(id);
        PageHelper.startPage(1, 1);
        List<ReviseVo> reviseVoList = omcReviseMapper.queryListWithPage(reviseQueryDto);
        if (PublicUtil.isEmpty(reviseVoList) || reviseVoList.size() < 1) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038028);
        }

        ReviseVo reviseVo = reviseVoList.get(0);

        // 查询调房调级缴费信息
        List<ReviseItemVo> reviseItemVoList = omcReviseItemService.queryListByReviseId(id);
        reviseVo.setReviseItemVoList(reviseItemVoList);

        // 查询调房调级套餐信息
        List<ReviseSetMealVo> reviseSetMealVoList = omcReviseSetMealService.queryListByReviseId(id);
        // 移除不可调整的项
        for (ReviseSetMealVo rsmv : reviseSetMealVoList) {
            Iterator<ReviseSetMealItemVo> iterator = rsmv.getReviseSetMealItemVoList().iterator();
            while (iterator.hasNext()) {
                ReviseSetMealItemVo rsmitv = iterator.next();
                if (!rsmitv.getIsAdjust().equals(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST)) { // 如果不可调整
                    iterator.remove();
                }
            }
        }
        reviseVo.setReviseSetMealVoList(reviseSetMealVoList);

        // 查询调房调级房间信息
        List<ReviseBedVo> reviseBedVoList = omcReviseBedService.queryListByReviseId(id);
        reviseVo.setReviseBedVoList(reviseBedVoList);

        return reviseVo;
    }

    /**
     * query revise comment by revise id
     *
     * @param id the revise id
     * @return the revise comment list
     */
    @Override
    public List<MyCommentVo> queryCommentById(Long id) {

        // 查询调房调级基本信息
        OmcRevise omcRevise = omcReviseMapper.selectByPrimaryKey(id);
        if (PublicUtil.isEmpty(omcRevise)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038028);
        }

        List<MyCommentVo> myCommentVoList = Lists.newArrayList();

        // 根据流程Id查询批注
        String processInstanceId = omcRevise.getProcessInstanceId();
        List<Comment> commentList = taskService.getProcessInstanceComments(processInstanceId);
        for (Comment c : commentList) {
            MyCommentVo myCommentVo = new MyCommentVo();
            myCommentVo.setUserId(c.getUserId());
            myCommentVo.setMessage(c.getFullMessage());
            myCommentVo.setTime(c.getTime());

            myCommentVoList.add(myCommentVo);
        }

        Collections.reverse(myCommentVoList);

        return myCommentVoList;
    }

    @Test
    public void main() throws IOException {
        //String date = "2019-09-17";
        //Integer realDays = DateUtil.getDaysByMonth(date);

        //System.out.println("realDays = " + realDays);

        BigDecimal paysPercent = new BigDecimal((float) 13 / 31);

        System.out.println("paysPercent = " + paysPercent);
    }

    @Test
    public void comp() {

        BigDecimal zero = BigDecimal.ZERO;
        BigDecimal degree = new BigDecimal("0.00");


        int ret = zero.compareTo(degree);

        if (zero.equals(degree)) {
            System.out.println("equal");
        } else {
            System.out.println("not equal");
        }

        System.out.println("ret = " + ret);
    }

    /**
     * apply revise
     *
     * @param reviseDto    the revise dto
     * @param loginAuthDto the login auth dto
     * @return the int.
     */
    @Override
    public Integer apply(ReviseDto reviseDto, LoginAuthDto loginAuthDto) {

        // 调整前 - 收费列表
        List<OmcReviseItem> beforeReviseItemList = Lists.newArrayList();
        // 调整后 - 收费列表
        List<OmcReviseItem> afterReviseItemList = Lists.newArrayList();

        Integer oldmanId = reviseDto.getOldmanId();
        Long groupId = loginAuthDto.getGroupId();
        // 校验老人是否可以进行调房调级
        // 获取用户是否为班长
        NursingGroup nursingGroup = new NursingGroup();
        nursingGroup.setUserId(loginAuthDto.getUserId());
        nursingGroup = omcGroupService.selectOne(nursingGroup);
        if (nursingGroup == null) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038001);
        }
        ReviseOldmanQueryDto reviseOldmanQueryDto = new ReviseOldmanQueryDto();
        reviseOldmanQueryDto.setNursingGroupId(nursingGroup.getId());
        reviseOldmanQueryDto.setGroupId(loginAuthDto.getGroupId());

        // 根据班组查询看护的房间
        List<Integer> roomIdList = omcNursingRoomBindMapper
                .queryRoomIdListByNursingGroupId(reviseOldmanQueryDto.getNursingGroupId());
        if (PublicUtil.isEmpty(roomIdList)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038011);
        }
        reviseOldmanQueryDto.setRoomIdList(roomIdList);
        reviseOldmanQueryDto.setGroupId(loginAuthDto.getGroupId());
        reviseOldmanQueryDto.setOldmanId(oldmanId);
        List<ReviseOldmanVo> reviseOldmanVoList = omcReviseMapper.queryOldmanList(reviseOldmanQueryDto);
        if (PublicUtil.isEmpty(reviseOldmanVoList)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038012);
        }
        String oldmanName = reviseOldmanVoList.get(0).getOldmanName();
        String inDate = reviseOldmanVoList.get(0).getInDate();

        // 查询老人--人员类别
        Long peopleType = omcOldManSupplementMapper.selectPeopleTypeByOldmanId(oldmanId);

        omcOldmanStatusService.oldmanReviseIng(oldmanId);

        //***************** 校验调房调级参数 *****************//
        // 调房调级日期参数校验
        String date = reviseDto.getDate();
        // 不能早于入院日期
        if (date.compareTo(inDate) <= 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038035);
        }

        // 不能早于之前已经调整的日期
        String reviseDate = omcReviseMapper.queryLastReviseDateByOldmanId(reviseDto.getOldmanId());
        if (PublicUtil.isNotEmpty(reviseDate) && date.compareTo(reviseDate) <= 0) {
            log.warn("reviseDate ==> {}, date ==> {}", reviseDate, date);
            throw new OmcBizException(ErrorCodeEnum.OMC10038016);
        }

        // 计算实际调整天数
        /**
         * 调整退费周期数 = （周期最大天数 - 实际调整天数（节点天数）） / 周期总条数
         * ** TIPS **
         * 1、周期最大天数 - 实际调整天数 < 0，调整退费周期数为0
         * 2、若周期退费数 > 1，调整退费周期数据为1
         */
        // 查询调房退费周期数
        ReviseDaysDto reviseDaysDto = new ReviseDaysDto();
        reviseDaysDto.setGroupId(groupId);
        reviseDaysDto.setCheckInDate(DateUtil.stringToDate(inDate));
        reviseDaysDto.setReviseDate(DateUtil.stringToDate(reviseDto.getDate()));
        ReviseDaysVo reviseDaysVo = omcReturnFeeConfigService.queryReviseDaysVo(reviseDaysDto);

        // 不能晚于当前周期
        String curDate = DateUtil.getDateStr(new Date());
        if (curDate.compareTo(DateUtil.getDateStr(reviseDaysVo.getLastDate())) < 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038041);
        }

        // 不能早于当前周期
        if (curDate.compareTo(DateUtil.getDateStr(reviseDaysVo.getNextDate())) >= 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038040);
        }

        // 查询最大周期数，周期总条数，请假退费天数，扣除请假天数
        // 计算调整退费周期数
        // 补缴天数
        // 若补缴天数 < 0 则补缴天数为0天
        // 若补缴天数 > 周期总天数 则补缴天数为周期总天数

        int payDays = reviseDaysVo.getPayDays();
        // 判断补缴天数计算是否正确
        if (!reviseDto.getPayDays().equals(payDays)) {  // 前端计算和后台计算的补缴天数不同
            throw new OmcBizException(ErrorCodeEnum.OMC10038019, payDays);
        }

        // 调整退费周期数 -- 补缴天数（周期最大天数 - 节点天数（该日期在当前月是第多少天）） / 周期总条数
        /**
         * @date    2019-10-14
         * @author  chisj
         * @desc    先计算补缴周期数，计算结果四舍五入
         * 调整补缴周期数 = 补缴天数 / 本周期总天数
         */
        BigDecimal payPercent = reviseDaysVo.getPayPercent();
        // 调整日期的周期消费周期数 = 本周期预缴周期数 - 调整补缴周期数
        BigDecimal usedPercent = reviseDaysVo.getUsedPercent();
        log.info("调整退费周期数 ===》 补缴天数【{}】，周期总天数【{}】，" +
                        "周期最大天数【{}】，消费周期数【{}】， 调整周期数【{}】",
                payDays, reviseDaysVo.getCycleTotalDays(),
                reviseDaysVo.getCycleMaxDays(), usedPercent, payPercent);

        /**
         * 购买套餐期间发生了调房调级（调房调级的时候，还有一些项目的套餐剩余次数未使用完，不为0）
         * 则需要对套餐进行退费
         *
         * 套餐退费的公式 = 项目一剩余次数 * 项目一退费标准 + 项目二剩余次数 * 项目二退费标准...
         *
         * 套餐退费方案
         *  1、若调整后，没有选中调整前的套餐的服务项，将套餐的剩余时间全部退费
         *  2、若调整后，选中的服务项和调整前的服务项相同，则套餐退费金额为0（不需要退费）
         */

        // 查询该老人的缴费信息
        /**
         * @date    2019-10-14
         * @author  chisj
         * @desc    修改bug #3463 调整前有一个公共服务费不可调整
         *
         * 修改思路：
         *      仅查询不可调整的缴费信息
         */
        Map<Long, OldmanPaymentFeeVo> oldmanPaymentFeeVoMap = Maps.newHashMap();
        GroupPaymentFeeQueryDto groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setOldmanId(oldmanId);
        groupPaymentFeeQueryDto.setIsAdjust(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST);
        List<OldmanPaymentFeeVo> oldmanPaymentFeeVoList = omcCycleExpenseItemMapper
                .queryOldmanPaymentFeeByOldmanId(groupPaymentFeeQueryDto);
        if (PublicUtil.isEmpty(oldmanPaymentFeeVoList)) {
            log.warn("老人无缴费信息");
        } else {
            oldmanPaymentFeeVoMap = oldmanPaymentFeeVoList.stream()
                    .collect(Collectors.toMap(OldmanPaymentFeeVo::getExpenseItemId, item -> item));
        }

        // 查询该机构的收费信息
        Map<Long, GroupPaymentFeeItemVo> groupPaymentFeeItemVoMap = Maps.newHashMap();
        groupPaymentFeeQueryDto = new GroupPaymentFeeQueryDto();
        groupPaymentFeeQueryDto.setGroupId(loginAuthDto.getGroupId());
        groupPaymentFeeQueryDto.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);
        groupPaymentFeeQueryDto.setIsAdjust(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST);
        List<GroupPaymentFeeVo> groupPaymentFeeVoList = omcExpenseTypeModelCodeMapper
                .queryGroupPaymentFeeByGroupId(groupPaymentFeeQueryDto);
        if (PublicUtil.isEmpty(groupPaymentFeeVoList)) {
            log.warn("机构无缴费信息");
        }

        // 可选择费用项目转Map集合
        for (GroupPaymentFeeVo gpfv : groupPaymentFeeVoList) {
            // 根据费用列表 - 人员类别查询
            if (PublicUtil.isNotEmpty(peopleType)) {
                // 如果无人员类型 则不需要查询人员类别减免
                OmcOldManTypeIetype omtit = new OmcOldManTypeIetype();
                omtit.setUserTypeId(peopleType);
                omtit.setItemId(gpfv.getExpenseTypeId());
                try {
                    omtit = omcOldManTypeIetypeMapper.selectOne(omtit);
                    if (PublicUtil.isNotEmpty(omtit)) {
                        gpfv.setPrecent(omtit.getPrecent());
                    }
                } catch (Exception e) {
                    throw new OmcBizException(ErrorCodeEnum.OMC10038013);
                }
            }
            for (ExpenseItem item : gpfv.getExpenseItemList()) {
                GroupPaymentFeeItemVo gpfiv = new GroupPaymentFeeItemVo();
                BeanUtils.copyProperties(item, gpfiv);
                BeanUtils.copyProperties(gpfv, gpfiv);
                groupPaymentFeeItemVoMap.put(item.getExpenseItemId(), gpfiv);
            }
        }

        // 判断调整后是否选中调整前的套餐服务项

        // 查询老人最近一次的入院账单Id
        Long billId = omcOldManBillService.queryOldmanCheckInBillId(oldmanId);
        if (billId == null) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038012);
        }

        boolean bed_flag = false;
        Integer bedId = reviseDto.getBedId();
        OldmanBedRoomBuildingVo afterOldmanBedRoomBuildingVo = null;

        // TODO 计算公式调整，以下计算公式作废
        /**
         * （调整后每周期费用 - 调整前每周期费用） * 调整退费周期数
         * ** TIPS **
         * 1、调整前每周期费用合计 = 收费项一实际费用 + 收费项二实际费用+... （不包括有剩余套餐次数）
         * 2、调整后每周期费用合计 = 收费项一收费标准 - （收费项一收费标准 * 人员类别减免比例） - 收费项一人工减免 + ...
         */
        // 差额计算
        // TODO 新的调整差额计算公式
        /**
         * 调整差额 = 套餐退费项目调整差额 + 非套餐项目调整差额
         *
         * 非套餐项目调整差额 = （调整补缴周期数） * 补缴项目（调整后差额 - 调整前差额）
         */
        BigDecimal noSetMealAgio = BigDecimal.ZERO;
        BigDecimal setMealAgio = BigDecimal.ZERO;
        Map<Long, ReviseTmpItemVo> reviseTmpItemVoMap = Maps.newHashMap();
        Map<Long, ReviseTmpItemVo> setMealReviseTmpItemVoMap = Maps.newHashMap();
        //List<ReviseTmpItemVo> reviseTmpItemVos = Lists.newArrayList();  // 补缴项目列表
        //List<ReviseTmpItemVo> setMealReviseTmpItemVos = Lists.newArrayList();  // 补缴项目列表

        // 老人调整后收费项
        BigDecimal after = new BigDecimal(0);
        Map<Long, OmcReviseItem> afterReviseItemMap = Maps.newHashMap();
        for (GroupPaymentFeeDto gpfd : reviseDto.getGroupPaymentFeeDtoList()) {
            Long expenseItemId = gpfd.getExpenseItemId();
            GroupPaymentFeeItemVo gpfiv = groupPaymentFeeItemVoMap.get(expenseItemId);
            if (PublicUtil.isEmpty(gpfiv)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038021, expenseItemId);
            }
            // 人员类别减免费用 = 收费标准 * 减免比例 / 100
            BigDecimal userTypeRateRefief = gpfiv.getChargeStandard()
                    .multiply(new BigDecimal(gpfiv.getPrecent()))
                    .divide(ReviseConstant.HUNDRED)
                    .setScale(2, BigDecimal.ROUND_HALF_UP);
            if (!userTypeRateRefief.equals(gpfd.getUserTypeRateRefief())) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038022, expenseItemId, gpfiv.getChargeStandard(),
                        gpfiv.getPrecent(), userTypeRateRefief);
            }

            // 实际费用 = 实际费用 - 人员类别减免 - 人工减免
            BigDecimal actualFee = gpfiv.getChargeStandard()
                    .subtract(userTypeRateRefief)
                    .subtract(gpfd.getUserRateRefief());
            if (!actualFee.equals(gpfd.getActualFee())) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038023, expenseItemId, gpfiv.getChargeStandard(),
                        gpfiv.getPrecent(), userTypeRateRefief);
            }
//            OldmanSetMealItemVo osmiv = copyOldmanSetMealItemVoMap.get(expenseItemId);
//            if (PublicUtil.isNotEmpty(osmiv)) { // 勾选的服务项是在套餐内
//                // 套餐的剩余时间全部退费，套餐剩余次数清零
//                if (osmiv.getResidueDegree().equals(new BigDecimal(0))) {
//
//                } else {    // 该服务项不参与计算差额
//                    gpfd.setResidueDegree(BigDecimal.ZERO);
//                    gpfd.setComp(false);    // 不参与差额计算
//                    copyOldmanSetMealItemVoMap.remove(expenseItemId);
//                    beforeOldmanSetMealItemVoMap.put(expenseItemId, osmiv);
//                }
//            } else {
//                // 不在套餐里面的周期剩余缴费次数
//                // gpfd.setResidueDegree(osmiv.getResidueDegree());    // 调整后还是有剩余周期数
//            }

            // 判断是否有床位费
            if (gpfiv.getExpenseTypeCode().equals(Constant.EXPENSE_TYPE_CODE_BED)) {
                // 必须选择床位
                bed_flag = true;
            }

            // 判断收费项Id是否存在
//            if (gpfd.isComp()) {
//                log.info("调整后差额计算 ===》 收费项目Id【{}】,名称【{}】，收费标准【{}】，类别减免【{}】，人工减免【{}】，实际收费【{}】",
//                        expenseItemId, gpfiv.getItemName(), gpfiv.getChargeStandard(),
//                        userTypeRateRefief, gpfd.getUserRateRefief(), actualFee);
//                after = after.add(actualFee);
//            }

            OmcReviseItem omcReviseItem = new OmcReviseItem();

            omcReviseItem.setAdjustOrder(2);    // 调整后
            omcReviseItem.setActualFee(actualFee);
            omcReviseItem.setUserRateRefief(gpfd.getUserRateRefief());
            omcReviseItem.setUserTypeRateRefief(userTypeRateRefief);
            omcReviseItem.setAmount(0);
            omcReviseItem.setModelCode(gpfiv.getModelCode());
            omcReviseItem.setIsAdjust(gpfiv.getIsAdjust());
            omcReviseItem.setIsLeaveReturn(gpfiv.getIsLeaveReturn());
            omcReviseItem.setIsOutReturn(gpfiv.getIsOutReturn());
            omcReviseItem.setIsFixedPrice(gpfiv.getIsFixedPrice());
            omcReviseItem.setCostType(gpfiv.getCostType());
            omcReviseItem.setExpenseItemId(gpfiv.getExpenseItemId());
            omcReviseItem.setItemFee(gpfiv.getChargeStandard());
            omcReviseItem.setItemName(gpfiv.getItemName());
            omcReviseItem.setItemType(gpfiv.getExpenseTypeName());
            omcReviseItem.setUsedDegree(BigDecimal.ZERO);
            omcReviseItem.setResidueDegree(gpfd.getResidueDegree());
            omcReviseItem.setExpenseTypeId(gpfiv.getExpenseTypeId());
            omcReviseItem.setCode(gpfiv.getExpenseTypeCode());
            omcReviseItem.setUpdateInfo(loginAuthDto);

            /**
             * 差额计算
             *
             * 判断是否在已经预缴
             */
            OldmanPaymentFeeVo opfv = oldmanPaymentFeeVoMap.get(omcReviseItem.getExpenseItemId());
            ReviseTmpItemVo reviseTmpItemVo = getReviseTmpItemVo(opfv, omcReviseItem, payPercent);
            reviseTmpItemVoMap.put(reviseTmpItemVo.getExpenseItemId(), reviseTmpItemVo);
            if (PublicUtil.isNotEmpty(opfv)) {
                opfv.setNoSetMealReturn(false);
            }

            afterReviseItemMap.put(omcReviseItem.getExpenseItemId(), omcReviseItem);
            afterReviseItemList.add(omcReviseItem);
        }
        log.info("调整后差额合计 ===》【{}】", after);

        // TODO 计算非套餐项目调整差额
//        BigDecimal afterActualFee = BigDecimal.ZERO;
//        BigDecimal beforeActualFee = oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()).getActualFee();
//        OmcReviseItem omcReviseItem = afterReviseItemMap.get(osmiv.getExpenseItemId());
//        if (PublicUtil.isEmpty(omcReviseItem)) {
//            afterActualFee = omcReviseItem.getActualFee();
//        }
//        // 非套餐收费项调整差额 = 调整周期数 * （调整后 - 调整前）
//        BigDecimal agio = payPercent.multiply(afterActualFee.subtract(beforeActualFee));
//        noSetMealAgio = noSetMealAgio.add(agio);
//        log.info("非套餐项目调整差额计算 ===》" +
//                        "类型[{}], 类型Id[{}], 名称[{}], 名称Id[{}], 调整前[{}],调整后[{}],差额[{}],差额合计[{}]",
//                omcReviseItem.getItemType(), omcReviseItem.getExpenseItemId(), omcReviseItem.getItemName(), omcReviseItem.getExpenseItemId(),
//                beforeActualFee, afterActualFee, agio, noSetMealAgio);

        // 套餐退费金额计算
        BigDecimal packFee = BigDecimal.ZERO;
        //BigDecimal packFee = new BigDecimal("0.00");
        // 查询老人入院选择的套餐 ==> 上一个账单的套餐
        Map<Long, OldmanSetMealItemVo> oldmanSetMealItemVoMap = Maps.newHashMap();
        // 用于判断调整后服务项是否包含套餐服务项
        Map<Long, OldmanSetMealItemVo> copyOldmanSetMealItemVoMap = Maps.newHashMap();
        // 用于标记是否调整前的收费项进行差额计算
        Map<Long, OldmanSetMealItemVo> beforeOldmanSetMealItemVoMap = Maps.newHashMap();
        List<OldmanSetMealVo> oldmanSetMealVoList = omcBillMealService.queryOldmanSetMealByBillId(billId);
        if (PublicUtil.isNotEmpty(oldmanSetMealVoList)) {
            // 老人选中套餐
            for (OldmanSetMealVo osmv : oldmanSetMealVoList) {
                for (OldmanSetMealItemVo osmiv : osmv.getOldmanSetMealItemVoList()) {
                    OldmanPaymentFeeVo opfv = oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId());  // 调整前的收费项
                    OmcReviseItem omcReviseItem = afterReviseItemMap.get(osmiv.getExpenseItemId()); // 调整后的收费项
                    if (PublicUtil.isEmpty(opfv)) {
                        // 套餐项目不在周期收费中，不进行退费
                        log.warn("套餐项目不在调整周期收费中 ====》 ExpenseItemId =【{}】", osmiv.getExpenseItemId());
                    } else {
                        // 账单开始时的套餐剩余数
                        BigDecimal residueDegree = osmiv.getUsedDegree().add(osmiv.getResidueDegree());
                        opfv.setNoSetMealReturn(false); // 不进行非套餐差额计算
                        // TODO 剩余周期数计算公式修改
                        if (BigDecimal.ZERO.compareTo(residueDegree) == 0) {    // 套餐使用完了，按正常项目计费
                            // TODO 非套餐退费项目调整差额
                            ReviseTmpItemVo reviseTmpItemVo = reviseTmpItemVoMap.get(osmiv.getExpenseItemId());
                            if (PublicUtil.isEmpty(reviseTmpItemVo)) {
                                reviseTmpItemVo = getReviseTmpItemVo(opfv, omcReviseItem, payPercent);
                                reviseTmpItemVoMap.put(reviseTmpItemVo.getExpenseItemId(), reviseTmpItemVo);
                            }

                        } else {
                            // 判断是否套餐退费
                            if (PublicUtil.isNotEmpty(omcReviseItem)) {    // 调整后没有该收费项 套餐退费
                                reviseTmpItemVoMap.remove(osmiv.getExpenseItemId());
                                // 判断套餐剩余次数和周期使用数
                                if (residueDegree.compareTo(usedPercent) <= 0) {
                                    // 套餐剩余次数不够已经使用的天数，已经在使用正常的费用了
                                    // 套餐退费金额为 0
                                    // TODO 套餐收费退费调整差额
                                    ReviseTmpItemVo reviseTmpItemVo = getReviseTmpItemVo(opfv, omcReviseItem, payPercent);
                                    setMealReviseTmpItemVoMap.put(osmiv.getExpenseItemId(), reviseTmpItemVo);
                                    osmiv.setUsedDegree(residueDegree);
                                    osmiv.setResidueDegree(BigDecimal.ZERO);
                                } else {
                                    // 调整时套餐剩余周期数
                                    BigDecimal setMealReturnPercent = residueDegree.subtract(usedPercent); // 该条件下大于0
                                    osmiv.setUsedDegree(usedPercent);
                                    osmiv.setResidueDegree(setMealReturnPercent);
                                    if (setMealReturnPercent.compareTo(payPercent) >= 0) {
                                        // 套餐收费退费差额为0
                                    } else {
                                        // 套餐收费退费差额 = (调整补缴周期数-套餐退费周期数)*(调整项目调整后价格-调整项目调整前原价)
                                        ReviseTmpItemVo reviseTmpItemVo = getReviseTmpItemVo(opfv, omcReviseItem, payPercent.subtract(setMealReturnPercent));
                                        setMealReviseTmpItemVoMap.put(osmiv.getExpenseItemId(), reviseTmpItemVo);
                                    }
                                }
                                omcReviseItem.setUsedDegree(osmiv.getUsedDegree());
                                omcReviseItem.setResidueDegree(osmiv.getResidueDegree());
                            } else {
                                // 套餐退费
                                if (residueDegree.compareTo(usedPercent) > 0) {
                                    // 套餐退费 = (套餐剩余周期数 - 使用周期数) * 退费标准
                                    BigDecimal setMealReturnPercent = residueDegree.subtract(usedPercent); // 该条件下大于0
                                    packFee = packFee.add(setMealReturnPercent.multiply(osmiv.getReturnStandard()).setScale(2, BigDecimal.ROUND_HALF_UP));
                                    log.info("套餐退费-全退：==》 项目名[{}],项目Id[{}],退费周期数[{}]", osmiv.getExpenseItemName(), osmiv.getExpenseItemId(), setMealReturnPercent);
                                    osmiv.setUsedDegree(BigDecimal.ZERO);
                                    osmiv.setResidueDegree(BigDecimal.ZERO);
                                }
                            }
                        }
                        // osmiv.setResidueDegree(oldmanPaymentFeeVoMap.get(osmiv.getExpenseItemId()).getResidueDegree());
                    }
                    //oldmanSetMealItemVoMap.put(osmiv.getExpenseItemId(), osmiv);
                    //copyOldmanSetMealItemVoMap.put(osmiv.getExpenseItemId(), osmiv);
                }
            }
        }


        // TODO 新的套餐退费计算公式
        /**
         * 套餐退费周期数 = 套餐退费项在调整日期时的剩余周期数
         * 调整账单周期开始日期的套餐剩余周期数 - 调整日期周期消费周期数（usedPercent）
         * 调整账单周期开始日期的套餐剩余周期数 = 套餐使用次数（usedDegree）+剩余次数（residueDegree）
         *
         */

        // TODO 新的调整差额计算公式
        /**
         * 调整差额 = 套餐退费项目调整差额 + 非套餐项目调整差额
         *
         * 非套餐项目调整差额 = （调整补缴周期数） * 补缴项目（调整后差额 - 调整前差额）
         */
        // TODO 计算非套餐项目调整差额
//        BigDecimal noSetMealAgio = BigDecimal.ZERO;
//        List<ReviseTmpItemVo> reviseTmpItemVos = Lists.newArrayList();  // 补缴项目列表
//        for (ReviseTmpItemVo tmp : reviseTmpItemVos) {
//            noSetMealAgio = noSetMealAgio.add(payPercent.multiply(tmp.getAgio()));
//            log.info("非套餐项目调整差额计算 ===》" +
//                            "类型[{}], 类型Id[{}], 名称[{}], 名称Id[{}], 调整前[{}],调整后[{}],差额[{}],差额合计[{}]",
//                    tmp.getItemType(), tmp.getExpenseItemId()), tmp.getItemName(), tmp.getExpenseItemId(),
//                    tmp.getBeforeFee(), tmp.getAfterFee(), tmp.getAgio(), noSetMealAgio);
//        }


        OldmanBedRoomBuildingVo beforeOldmanBedRoomBuildingVo =
                oldmanService.queryOldmanBedRoomBuildingByOldmanId(oldmanId);

        // 是否有调整床位
        boolean flag = false;

        if (bed_flag) { // 床位不能为空
            flag = true;
            if (bedId == null) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038025);
            }

            afterOldmanBedRoomBuildingVo = oldmanService.queryOldmanBedRoomBuildingByBedId(bedId);
            if (PublicUtil.isEmpty(afterOldmanBedRoomBuildingVo)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038026);
            }
            if (PublicUtil.isNotEmpty(afterOldmanBedRoomBuildingVo.getOldmanId())) {
                if (PublicUtil.isNotEmpty(beforeOldmanBedRoomBuildingVo)
                        && PublicUtil.isNotEmpty(beforeOldmanBedRoomBuildingVo.getBedId())
                        && beforeOldmanBedRoomBuildingVo.getBedId().equals(bedId)) {
                    log.warn("床位调整 ===> 未改变床位");
                    flag = false;
                } else {
                    log.error("床位调整 ===> 已经有人入住 oldmanId = 【{}】", afterOldmanBedRoomBuildingVo.getOldmanId());
                    throw new OmcBizException(ErrorCodeEnum.OMC10038027);
                }
            }
        }

        // 老人调整前收费项
        for (OldmanPaymentFeeVo opfv : oldmanPaymentFeeVoList) {
            Long expenseItemId = opfv.getExpenseItemId();
            if (opfv.isNoSetMealReturn()) {
                ReviseTmpItemVo reviseTmpItemVo = reviseTmpItemVoMap.get(expenseItemId);
                if (PublicUtil.isEmpty(reviseTmpItemVo)) {
                    reviseTmpItemVo = getReviseTmpItemVo(opfv, null, payPercent);
                    reviseTmpItemVoMap.put(expenseItemId, reviseTmpItemVo);
                }
            }
            beforeReviseItemList.add(getBeforeReviseItem(opfv, loginAuthDto));
        }
//        log.info("调整前差额合计 ===》【{}】", before);

        // TODO 非套餐调整差额合计
        for (ReviseTmpItemVo value : reviseTmpItemVoMap.values()) {
            noSetMealAgio = noSetMealAgio.add(value.getAgioTotal());
            log.info("非套餐差额合计 ==》名称[{}],Id[{}],调整前[{}],调整后[{}],调整系数[{}],差额[{}],累计差额[{}]",
                    value.getItemName(),value.getExpenseItemId(),value.getBeforeFee(),value.getAfterFee(),value.getPayPercent(),value.getAgioTotal(),noSetMealAgio);
        }

        // TODO 套餐调整差额合计
        for (ReviseTmpItemVo value : setMealReviseTmpItemVoMap.values()) {
            setMealAgio = setMealAgio.add(value.getAgioTotal());
            log.info("非套餐差额合计 ==》名称[{}],Id[{}],调整前[{}],调整后[{}],调整系数[{}],差额[{}],累计差额[{}]",
                    value.getItemName(),value.getExpenseItemId(),value.getBeforeFee(),value.getAfterFee(),value.getPayPercent(),value.getAgioTotal(),setMealAgio);
        }

        // 调整差额 = 非套餐调整差额，套餐调整差额
        BigDecimal agio = noSetMealAgio.add(setMealAgio);


        // 差额 = （调整后 - 调整前） * 调整周期数 （退费天数 / 周期总天数）
//        BigDecimal agio = after.subtract(before)
//                .multiply(new BigDecimal(payDays))
//                .divide(new BigDecimal(reviseDaysVo.getCycleTotalDays()), BigDecimal.ROUND_HALF_UP)
//                .setScale(2, BigDecimal.ROUND_HALF_UP);
//        log.info("调整差额 ===》【{}】", agio);
        if (agio.compareTo(reviseDto.getAgio()) != 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038024, agio);
        }

        // 遍历筛选后套餐项
//        for (OldmanSetMealItemVo osmiv : copyOldmanSetMealItemVoMap.values()) {
//            // 项目一剩余次数 * 项目一退费标准
//            packFee = packFee.add(osmiv.getResidueDegree().multiply(osmiv.getReturnStandard()));
//            log.info("套餐退费 ===》收费项目Id【{}】，名称【{}】剩余次数【{}】的退费标准【{}】，退费金额【{}】",
//                    osmiv.getExpenseItemId(), osmiv.getExpenseItemName(), osmiv.getResidueDegree(),
//                    osmiv.getReturnStandard(), packFee);
//        }
        // 判断退费金额是否正确
        // packFee = packFee.setScale(2, BigDecimal.ROUND_HALF_UP);
        if (packFee.compareTo(reviseDto.getPackFee()) != 0) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038020, packFee);
        }

        // TODO 请假退费计算
        /**
         * 生成调房调级记录单，将本次缴费周期到调房调级日期的请假结算退费结算，将请假时长清空
         *
         * 调房调级请假退费金额 =
         *  （请假退费周期数 * 调整前周期计算合计费用（不包含套餐） + 请假周期数 * 套餐退费公式）
         */
        // 请假退费金额计算

        // 请假天数计算 当前周期内的
        OmcOldLeaveQueryDto omcOldLeaveQueryDto = new OmcOldLeaveQueryDto();
        omcOldLeaveQueryDto.setOldManId(oldmanId.longValue());
        omcOldLeaveQueryDto.setAdjustDate(reviseDto.getDate());
        omcOldLeaveQueryDto.setGroupId(groupId);
        OmcAdjustRefundData omcAdjustRefundData = omcOldLeaveService.showLeaveRefundFee(omcOldLeaveQueryDto);
        if (omcAdjustRefundData != null) {
            // 校验请假天数和请假退款金额
            if (!omcAdjustRefundData.getRefundDays().equals(reviseDto.getLeaveDays())) {
                // 请假天数不对
                throw new OmcBizException(ErrorCodeEnum.OMC10038038, packFee);
            }

            if (!omcAdjustRefundData.getRefundFee().equals(reviseDto.getLeaveFee())) {
                // 请假退款不对
                throw new OmcBizException(ErrorCodeEnum.OMC10038039, packFee);
            }
        }

        /**
         * 当服务项变更导致套餐被取消的情况下：
         * 消费合计 =
         *  套餐退费金额 + 请假退费金额 - （调整后每周期费用 - 调整前每周期费用（不包含套餐剩余次数为0内的项目）） * 调整退费周期数
         *
         * 项目变更，套餐未取消的情况
         * 消费合计 =
         *  请假退费金额 + （调整后每周期费用 - 调整前每周期费用（不包含套餐剩余次数为0内的项目）） * 调整退费周期数
         *
         * 当余额 - 消费金额 > 0
         *  调房调级缴费单显示的应缴合计为0，同时账户余额 = 调整前余额 - 消费金额
         *
         * 当余额 - 消费金额 < 0
         *  调房调级缴费单显示的应缴合计为 - 退费，账户余额 = 调整前余额 - 消费金额
         */

        // 调整退费公式


        // 启动流程
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(ReviseConstant.REVISE_VAR_SERVICE, omcReviseVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), ReviseConstant.REVISE_VAR_SERVICE));
        variables.put(ReviseConstant.REVISE_VAR_ADMIT, omcReviseVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), ReviseConstant.REVISE_VAR_ADMIT));
        variables.put(ReviseConstant.REVISE_VAR_CHARGE, omcReviseVarService
                .queryVarByGroupIdAndKey(loginAuthDto.getGroupId(), ReviseConstant.REVISE_VAR_CHARGE));
        variables.put(ReviseConstant.REVISE_VAR_APPLY, loginAuthDto.getUserId().toString()); // 申请人
        // 调整后的床位
        System.out.println("床位调整状态 flag = " + flag);
        if (flag && PublicUtil.isNotEmpty(afterOldmanBedRoomBuildingVo)) {
            variables.put(ReviseConstant.REVISE_VAR_AFTER_BED, afterOldmanBedRoomBuildingVo.getBedId().toString());

            /**
             * @date    2019-11-27
             * @author  chisj
             * @desc    变更调房后的床位状态[调房预约]
             */
            Bed bed = new Bed();
            bed.setBedId(afterOldmanBedRoomBuildingVo.getBedId());
            bed.setStatus(Constant.BED_STATUS_REVISE);
            bedService.updateStatusById(bed);
        }

        ProcessInstance processInstance = omcActivitiService
                .startProcessInstanceByKeyAndTenantId(ReviseConstant.PROCESS_KEY_REVISE,
                        variables, loginAuthDto.getGroupId());

        // 查询当前任务
        Task task = omcActivitiService.getTaskByProcessInstanceId(processInstance.getProcessInstanceId());

        // 添加批注
        omcActivitiService.addTaskComment(task, loginAuthDto.getUserName() + "[班长]", "提交申请");

        // 完成调房调级申请
        taskService.complete(task.getId());

        OmcRevise omcRevise = new OmcRevise();
        // 添加调房调级
        BeanUtils.copyProperties(reviseDto, omcRevise);

        omcRevise.setProcessInstanceId(processInstance.getProcessInstanceId());
        omcRevise.setGroupId(loginAuthDto.getGroupId());
        omcRevise.setUpdateInfo(loginAuthDto);
        omcRevise.setState(ReviseConstant.REVISE_STATE_APPLY);
        omcRevise.setOldmanId(oldmanId);
        omcRevise.setOldmanName(oldmanName);
        omcRevise.setNursingGroupId(nursingGroup.getId());

        Integer result = omcReviseMapper.insertSelective(omcRevise);
        if (result < 1) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038015);
        }

        Long reviseId = omcRevise.getId();
        // 调整前费用、调整后费用入库
        List<OmcReviseItem> omcReviseItemList = Lists.newArrayList();
        omcReviseItemList.addAll(beforeReviseItemList);
        omcReviseItemList.addAll(afterReviseItemList);
        omcReviseItemService.batchSaveReviseItem(omcReviseItemList, reviseId);

        // 调整前套餐费用入库
        if (PublicUtil.isNotEmpty(oldmanSetMealVoList)) {
            // 老人选中套餐
            for (OldmanSetMealVo osmv : oldmanSetMealVoList) {
                OmcReviseSetMeal omcReviseSetMeal = new OmcReviseSetMeal();
                omcReviseSetMeal.setActualPrice(osmv.getActualPrice());
                omcReviseSetMeal.setDiscount(osmv.getDiscount());
                omcReviseSetMeal.setOriginalPrice(osmv.getOriginalPrice());
                omcReviseSetMeal.setReviseId(reviseId);
                omcReviseSetMeal.setSetMealId(osmv.getSetMealId());
                omcReviseSetMeal.setSetMealName(osmv.getSetMealName());
                omcReviseSetMeal.setSubPrice(osmv.getSubPrice());
                omcReviseSetMeal.setUpdateInfo(loginAuthDto);
                omcReviseSetMealService.save(omcReviseSetMeal);
                List<OmcReviseSetMealItem> omcReviseSetMealItemList = Lists.newArrayList();
                for (OldmanSetMealItemVo osmiv : osmv.getOldmanSetMealItemVoList()) {
                    OmcReviseSetMealItem omcReviseSetMealItem = new OmcReviseSetMealItem();
                    omcReviseSetMealItem.setReviseSetMealId(omcReviseSetMeal.getId());
                    omcReviseSetMealItem.setExpenseTypeId(osmiv.getExpenseTypeId());
                    omcReviseSetMealItem.setModelCode(osmiv.getModelCode());
                    omcReviseSetMealItem.setIsAdjust(osmiv.getIsAdjust());
                    omcReviseSetMealItem.setIsLeaveReturn(osmiv.getIsLeaveReturn());
                    omcReviseSetMealItem.setIsOutReturn(osmiv.getIsOutReturn());
                    omcReviseSetMealItem.setExpenseItemId(osmiv.getExpenseItemId());
                    omcReviseSetMealItem.setItemFee(osmiv.getChargeStandard());
                    omcReviseSetMealItem.setItemName(osmiv.getExpenseItemName());
                    omcReviseSetMealItem.setItemType(osmiv.getExpenseTypeName());
                    omcReviseSetMealItem.setUsedDegree(osmiv.getUsedDegree());
                    omcReviseSetMealItem.setResidueDegree(osmiv.getResidueDegree());
                    omcReviseSetMealItem.setReturnStandard(osmiv.getReturnStandard());
                    omcReviseSetMealItem.setTimes(osmiv.getTimes());
                    omcReviseSetMealItem.setRemark(osmiv.getRemark());
                    omcReviseSetMealItem.setCostType(osmiv.getCostType());
                    omcReviseSetMealItem.setContent(osmiv.getContent());
                    omcReviseSetMealItem.setUpdateInfo(loginAuthDto);
                    omcReviseSetMealItemList.add(omcReviseSetMealItem);
                }
                omcReviseSetMealItemService.batchSave(omcReviseSetMealItemList);
            }
        }

        // 调整前床、后位信息入库
        List<OmcReviseBed> omcReviseBedList = Lists.newArrayList();
//        OldmanBedRoomBuildingVo beforeOldmanBedRoomBuildingVo =
//                oldmanService.queryOldmanBedRoomBuildingByOldmanId(oldmanId);
        if (PublicUtil.isNotEmpty(beforeOldmanBedRoomBuildingVo)) {
            OmcReviseBed omcReviseBed = new OmcReviseBed();
            BeanUtils.copyProperties(beforeOldmanBedRoomBuildingVo, omcReviseBed);
            omcReviseBed.setBedOrder(1);
            omcReviseBed.setReviseId(reviseId);
            omcReviseBed.setLocation(beforeOldmanBedRoomBuildingVo.getRoomNo()
                    + beforeOldmanBedRoomBuildingVo.getRoomLink()
                    + beforeOldmanBedRoomBuildingVo.getBedNo());
            omcReviseBedList.add(omcReviseBed);
        }
        if (PublicUtil.isNotEmpty(afterOldmanBedRoomBuildingVo)) {
            OmcReviseBed omcReviseBed = new OmcReviseBed();
            BeanUtils.copyProperties(afterOldmanBedRoomBuildingVo, omcReviseBed);
            omcReviseBed.setBedOrder(2);
            omcReviseBed.setReviseId(reviseId);
            omcReviseBed.setLocation(afterOldmanBedRoomBuildingVo.getRoomNo()
                    + afterOldmanBedRoomBuildingVo.getRoomLink()
                    + afterOldmanBedRoomBuildingVo.getBedNo());
            omcReviseBedList.add(omcReviseBed);
        }

        omcReviseBedService.batchSave(omcReviseBedList);

        return result;
    }

    /**
     * 收费项调整差额计算
     *
     *
     * @param opfv
     * @param omcReviseItem
     * @param payPercent
     * @return
     */
    private ReviseTmpItemVo getReviseTmpItemVo(OldmanPaymentFeeVo opfv, OmcReviseItem omcReviseItem, BigDecimal payPercent) {

        ReviseTmpItemVo reviseTmpItemVo = new ReviseTmpItemVo();
        boolean flag = true;

        if (PublicUtil.isNotEmpty(opfv)) {
            flag = false;
            reviseTmpItemVo.setExpenseItemId(opfv.getExpenseItemId());
            reviseTmpItemVo.setExpenseTypeId(opfv.getExpenseTypeId());
            reviseTmpItemVo.setItemName(opfv.getItemName());
            reviseTmpItemVo.setItemType(opfv.getItemType());
            reviseTmpItemVo.setBeforeFee(opfv.getActualFee());
        }

        if (PublicUtil.isNotEmpty(omcReviseItem)) {
            if (flag) {
                reviseTmpItemVo.setExpenseItemId(omcReviseItem.getExpenseItemId());
                reviseTmpItemVo.setExpenseTypeId(omcReviseItem.getExpenseTypeId());
                reviseTmpItemVo.setItemName(omcReviseItem.getItemName());
                reviseTmpItemVo.setItemType(omcReviseItem.getItemType());
            }
            flag = false;
            reviseTmpItemVo.setAfterFee(omcReviseItem.getActualFee());
        }

        if (flag) {
            log.error("调整前和调整后的收费项不能都为null");
            throw new OmcBizException(ErrorCodeEnum.OMC10038037);
        }

        reviseTmpItemVo.setPayPercent(payPercent);
        reviseTmpItemVo.setAgio(reviseTmpItemVo.getAfterFee().subtract(reviseTmpItemVo.getBeforeFee()));
        reviseTmpItemVo.setAgioTotal(reviseTmpItemVo.getAgio().multiply(payPercent).setScale(2, BigDecimal.ROUND_HALF_UP));

        return reviseTmpItemVo;
    }

    /**
     * 获取调整前的收费项
     *
     * @param opfv  the oldman payment fee vo
     * @param loginAuthDto  the login auth dto
     *
     * @return  the omc revise item
     */
    private OmcReviseItem getBeforeReviseItem(OldmanPaymentFeeVo opfv, LoginAuthDto loginAuthDto) {

        OmcReviseItem omcReviseItem = new OmcReviseItem();

        omcReviseItem.setAdjustOrder(1);    // 调整前
        omcReviseItem.setActualFee(opfv.getActualFee());
        omcReviseItem.setAmount(opfv.getAmount());
        omcReviseItem.setCostType(opfv.getCostType());
        omcReviseItem.setExpenseItemId(opfv.getExpenseItemId());
        omcReviseItem.setItemFee(opfv.getItemFee());
        omcReviseItem.setItemName(opfv.getItemName());
        omcReviseItem.setItemType(opfv.getItemType());
        omcReviseItem.setUserRateRefief(opfv.getUserRateRefief());
        omcReviseItem.setUserTypeRateRefief(opfv.getUserTypeRateRefief());
        omcReviseItem.setUsedDegree(opfv.getUsedDegree());
        omcReviseItem.setResidueDegree(opfv.getResidueDegree());
        omcReviseItem.setExpenseTypeId(opfv.getExpenseTypeId());
        omcReviseItem.setCode(opfv.getCode());
        omcReviseItem.setUpdateInfo(loginAuthDto);
        omcReviseItem.setModelCode(opfv.getModelCode());
        omcReviseItem.setIsAdjust(opfv.getIsAdjust());
        omcReviseItem.setIsLeaveReturn(opfv.getIsLeaveReturn());
        omcReviseItem.setIsOutReturn(opfv.getIsOutReturn());
        omcReviseItem.setIsFixedPrice(opfv.getIsFixedPrice());

        return omcReviseItem;
    }

    /**
     * service approval revise
     *
     * @param reviseApprovalDto the revise approval dto
     * @param loginAuthDto      the login auth dto
     * @return the int.
     */
    @Override
    public Integer serviceApproval(ReviseApprovalDto reviseApprovalDto, LoginAuthDto loginAuthDto) {

        String processInstanceId;

        // 查询订单是否存在
        OmcRevise omcReviseQuery = omcReviseMapper.selectByPrimaryKey(reviseApprovalDto.getId());
        if (PublicUtil.isEmpty(omcReviseQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038028);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcReviseQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(ReviseConstant.PROCESS_KEY_REVISE)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(ReviseConstant.REVISE_TASK_SERVICE_APPROVAL)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        // String comment = ReviseConstant.REVISE_COMMENT_SERVICE_REFUSE;
        Integer state = ReviseConstant.REVISE_STATE_SERVICE_REFUSE;
        String msg = ReviseConstant.REVISE_VAR_MSG_REFUSE;
        String comment = reviseApprovalDto.getComment();
        if (reviseApprovalDto.getState().equals(ReviseConstant.REVISE_APRV_STATE_YES)) {
            msg = ReviseConstant.REVISE_VAR_MSG_CONFIRM;
            state = ReviseConstant.REVISE_STATE_SERVICE_AGREE;
            comment = ReviseConstant.REVISE_COMMENT_SERVICE_AGREE;
        } else {
            if (PublicUtil.isEmpty(comment)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038034);
            }
            omcOldmanStatusService.oldmanReviseEnd(omcReviseQuery.getOldmanId());

            /**
             * @date    2019-11-27
             * @author  chisj
             * @desc    变更调房后的床位状态[空床]
             */
            Map<String, Object> variable = taskService.getVariables(task.getId());
            Object afterBed = variable.get(ReviseConstant.REVISE_VAR_AFTER_BED);
            if (PublicUtil.isNotEmpty(afterBed)) {
                Bed bed = new Bed();
                bed.setBedId(Integer.parseInt(afterBed.toString()));
                bed.setStatus(Constant.BED_STATUS_ENPTY);
                bedService.updateStatusById(bed);
            }
        }
        taskService.setVariable(task.getId(), ReviseConstant.REVISE_VAR_MSG, msg);

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[服务部长]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        // 完成任务
        taskService.complete(task.getId());

        OmcRevise omcRevise = new OmcRevise();
        omcRevise.setId(reviseApprovalDto.getId());
        omcRevise.setUpdateInfo(loginAuthDto);
        omcRevise.setState(state);

        return omcReviseMapper.updateByPrimaryKeySelective(omcRevise);
    }

    /**
     * admit confirm revise
     *
     * @param reviseConfirmDto the revise confirm dto
     * @param loginAuthDto     the login auth dto
     * @return the int.
     */
    @Override
    public Integer admitConfirm(ReviseConfirmDto reviseConfirmDto, LoginAuthDto loginAuthDto) {

        String processInstanceId;

        // 查询订单是否存在
        OmcRevise omcReviseQuery = omcReviseMapper.selectByPrimaryKey(reviseConfirmDto.getId());
        if (PublicUtil.isEmpty(omcReviseQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038028);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcReviseQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(ReviseConstant.PROCESS_KEY_REVISE)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(ReviseConstant.REVISE_TASK_ADMIT_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

        String comment = ReviseConstant.REVISE_COMMENT_ADMIT_CONFIRM;
        Integer state = ReviseConstant.REVISE_STATE_ADMIT_CONFIRM;

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[接待室]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        // 完成任务
        taskService.complete(task.getId());

        OmcRevise omcRevise = new OmcRevise();
        omcRevise.setId(reviseConfirmDto.getId());
        omcRevise.setUpdateInfo(loginAuthDto);
        omcRevise.setState(state);

        return omcReviseMapper.updateByPrimaryKeySelective(omcRevise);
    }

    /**
     * charge confirm revise
     *
     * @param reviseConfirmDto the revise confirm dto
     * @param loginAuthDto     the login auth dto
     * @return the int.
     */
    @Override
    public Integer chargeConfirm(ReviseConfirmDto reviseConfirmDto, LoginAuthDto loginAuthDto) {

        String processInstanceId;
        Long id = reviseConfirmDto.getId();

        // 查询订单是否存在
        OmcRevise omcReviseQuery = omcReviseMapper.selectByPrimaryKey(id);
        if (PublicUtil.isEmpty(omcReviseQuery)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038028);
        }

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        List<String> roleCodeList = roleVoList.stream().map(r -> r.getRoleCode()).collect(Collectors.toList());

        processInstanceId = omcReviseQuery.getProcessInstanceId();
        Task task = taskService.createTaskQuery()
                .taskTenantId(loginAuthDto.getGroupId().toString())
                .processDefinitionKey(ReviseConstant.PROCESS_KEY_REVISE)
                .taskCandidateGroupIn(roleCodeList)
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(ReviseConstant.REVISE_TASK_CHARGE_CONFIRM)
                .singleResult();

        if (PublicUtil.isEmpty(task)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10032008);
        }

//        SendMessageRequest sendMessageRequest = new SendMessageRequest();
//        Long applyId = omcReviseQuery.getCreatorId();
//        log.info("申请人 applyId = {}", applyId);
//        sendMessageRequest.setGroupId(omcReviseQuery.getGroupId());
//        sendMessageRequest.setTagList(Lists.newArrayList(JiGuangConstant.TAG_PREFIX_USER + applyId));
//        sendMessageRequest.setUserIdList(Lists.newArrayList(applyId));
//        sendMessageRequest.setMsgCode(ReviseConstant.REVISE_FLOW_CHARGE_CONFIRM);
//        opcMessageService.pushByUser(sendMessageRequest);

        String comment = ReviseConstant.REVISE_COMMENT_CHARGE_CONFIRM;
        Integer state = ReviseConstant.REVISE_STATE_CHARGE_CONFIRM;

        // 设置用户id
        Authentication.setAuthenticatedUserId(loginAuthDto.getUserName() + "[收费室]");
        // 添加批注信息
        taskService.addComment(task.getId(), processInstanceId, comment);

        // 完成任务
        taskService.complete(task.getId());

        OmcRevise omcRevise = new OmcRevise();
        omcRevise.setId(id);
        omcRevise.setUpdateInfo(loginAuthDto);
        omcRevise.setState(state);

        // 床位入库
        Integer beforeBed = -1, afterBed = -1;
        boolean update_before = false, update_after = false;
        List<ReviseBedVo> reviseBedVoList = omcReviseBedService.queryListByReviseId(id);
        for (ReviseBedVo rbv : reviseBedVoList) {
            if (rbv.getBedOrder().equals(1)) {
                beforeBed = rbv.getBedId();
                update_before = true;
            }

            if (rbv.getBedOrder().equals(2)) {  // 调整后的床位
                afterBed = rbv.getBedId();
                update_after = true;
            }
        }

        if (update_after) {
            // 判断该床位是否有人入住
            OldmanBedRoomBuildingVo obrbv = oldmanService.queryOldmanBedRoomBuildingByBedId(afterBed);
            if (PublicUtil.isEmpty(obrbv)) {
                throw new OmcBizException(ErrorCodeEnum.OMC10038026);
            }
            Integer oldmanId = obrbv.getOldmanId();
            if (PublicUtil.isNotEmpty(oldmanId)) {  // 床上有人
                if (!omcReviseQuery.getOldmanId().equals(oldmanId)) {   // 床上不是调整的老人
                    throw new OmcBizException(ErrorCodeEnum.OMC10038027);
                } else {    // 对床位不做任何处理
                    update_before = false;
                }
            } else {    // 空床
                // 将老人入住到该床位
                Bed bed = new Bed();
                bed.setBedId(afterBed);
                bed.setStatus(2);   // 床位状态 - 有人
                // 拿到调整前的入住床位 如果调整前有床位，使用调整前的床位状态
                OmcOldmanStatus omcOldmanStatus = omcOldmanStatusService.queryByOldmanId(oldmanId);
                if (PublicUtil.isNotEmpty(omcOldmanStatus)) {
                    bed.setStatus(omcOldmanStatus.getLastStatus()); // 获取上一个入住状态
                }
                bed.setOldmanId(omcReviseQuery.getOldmanId());
                bedService.updateById(bed);
            }
        }

        if (update_before) {    // 清空之前入住床位
            bedService.cleanOldmanById(beforeBed);
        }

        // 账单入库
        OmcOldManBill omcOldManBill = getOmcOldManBillByRevise(omcReviseQuery);
        omcOldManBill.setUpdateInfo(loginAuthDto);
        List<BedNosVo> nos = bedService.selectAllNo(afterBed);
        if (PublicUtil.isNotEmpty(nos)){
           omcOldManBill.setBedNo(nos.get(0).getRoomNo()+nos.get(0).getRoomLink()+nos.get(0).getBedNo());
        }

        omcOldManBillService.save(omcOldManBill);

        // 账单 - 套餐入库
        List<OmcBillMeal> omcBillMealList = Lists.newArrayList();
        List<OmcBillSetMealItem> omcBillSetMealItemList = Lists.newArrayList();
        List<ReviseSetMealVo> reviseSetMealVoList = omcReviseSetMealService.queryListByReviseId(id);
        for (ReviseSetMealVo rsmv : reviseSetMealVoList) {
            OmcBillMeal omcBillMeal = new OmcBillMeal();
            BeanUtils.copyProperties(rsmv, omcBillMeal);
            omcBillMeal.setGroupId(omcReviseQuery.getGroupId());
            omcBillMeal.setBillId(omcOldManBill.getId());
            omcBillMeal.setUpdateInfo(loginAuthDto);
            /**
             * @date    2019-11-27
             * @author  chisj
             * @desc    修复bug 调整后，再次调整没有套餐名称
             */
            omcBillMeal.setMealName(rsmv.getSetMealName());
            omcBillMealList.add(omcBillMeal);
            for (ReviseSetMealItemVo rsmitv : rsmv.getReviseSetMealItemVoList()) {
                OmcBillSetMealItem omcBillSetMealItem = new OmcBillSetMealItem();
                BeanUtils.copyProperties(rsmitv, omcBillSetMealItem);
                omcBillSetMealItem.setSetmealId(rsmv.getSetMealId());
                omcBillSetMealItem.setGroupId(omcReviseQuery.getGroupId());
                omcBillSetMealItem.setBillId(omcOldManBill.getId());
                omcBillSetMealItem.setUpdateInfo(loginAuthDto);
                omcBillSetMealItem.setExpenseItemName(rsmitv.getItemName());
                omcBillSetMealItem.setExpenseTypeName(rsmitv.getItemType());
                omcBillSetMealItem.setChargeStandard(rsmitv.getItemFee());
                omcBillSetMealItem.setModelCode(rsmitv.getModelCode());
                omcBillSetMealItem.setRemark(rsmitv.getRemark());
                omcBillSetMealItemList.add(omcBillSetMealItem);
            }
        }
        omcBillMealService.batchSave(omcBillMealList);
        omcBillSetMealItemService.batchSave(omcBillSetMealItemList);

        // 账单详情入库
        // List<ReviseItemVo> reviseItemVoList = omcReviseItemService.queryListByReviseId(id);
        ReviseItemQueryDto reviseItemQueryDto = new ReviseItemQueryDto();
        reviseItemQueryDto.setReviseId(id);
        // reviseItemQueryDto.setAdjustOrder(2);   // 查询调整后的账单Id
        reviseItemQueryDto.setPageSize(65535);
        List<ReviseItemVo> reviseItemVoList = omcReviseItemService.queryListWithPage(reviseItemQueryDto);
        List<OmcBillItem> omcBillItemList = Lists.newArrayList();
        List<OmcCycleExpenseItem> omcCycleExpenseItemList = Lists.newArrayList();
        for (ReviseItemVo riv : reviseItemVoList) {
            OmcBillItem omcBillItem = getOmcBillItemByRevise(riv);
            omcBillItem.setGroupId(omcReviseQuery.getGroupId());
            omcBillItem.setUpdateInfo(loginAuthDto);
            omcBillItem.setBillId(omcOldManBill.getId());
            omcBillItemList.add(omcBillItem);
            if (riv.getAdjustOrder().equals(2)) {
                OmcCycleExpenseItem omcCycleExpenseItem = getOmcCycleExpenseItem(riv);
                omcCycleExpenseItem.setGroupId(omcReviseQuery.getGroupId());
                omcCycleExpenseItem.setUpdateInfo(loginAuthDto);
                omcCycleExpenseItem.setOldmanId((long) omcReviseQuery.getOldmanId());
                omcCycleExpenseItemList.add(omcCycleExpenseItem);
            }
        }
        omcBillItemService.batchSave(omcBillItemList);

        // 老人资金账户
        OmcOldManAccountFunds omcOldManAccountFunds = omcOldManAccountFundsService
                .queryByOldmanId(omcReviseQuery.getOldmanId());
        if (PublicUtil.isEmpty(omcOldManAccountFunds)) {
            throw new OmcBizException(ErrorCodeEnum.OMC10038030);
        }

        /**
         * 应缴合计
         * 1、当余额 - 消费金额 >= 0 调房调级缴费单显示的应缴合计为0，账户余额 = 调整前余额 - 消费金额
         * 2、当金额 - 消费合计 <  0 调房调级缴费单显示的应缴合计为 - 退费，账户余额 = 余额 - 消费金额
         */

        // 消费合计
        BigDecimal total = omcReviseQuery.getTotal();
        // 调整余额
        BigDecimal beforeAdjustBalance = omcOldManAccountFunds.getRemainder();
        // 实际合缴费用 total_fee
        BigDecimal totalFee;

        BigDecimal afterAdjustBalance = beforeAdjustBalance.subtract(total);
        int r = afterAdjustBalance.compareTo(BigDecimal.ZERO);
        if (r >= 0) {
            totalFee = BigDecimal.ZERO;
        } else {
            totalFee = afterAdjustBalance.multiply(new BigDecimal(-1));
            afterAdjustBalance = BigDecimal.ZERO;
        }

        // 老人请假退费结算
        omcOldLeaveService.closeReturnFeeByDate(omcReviseQuery.getOldmanId(), omcReviseQuery.getDate());

        // 老人资金账户入库
        omcOldManAccountFunds.setActPaidFee(omcOldManAccountFunds.getActPaidFee().add(totalFee));
        omcOldManAccountFunds.setMonetary(omcOldManAccountFunds.getMonetary().add(total));
        omcOldManAccountFunds.setRemainder(afterAdjustBalance);
        omcOldManAccountFunds.setUpdateInfo(loginAuthDto);
        omcOldManAccountFundsService.update(omcOldManAccountFunds);

        // 账单统计入库
        OmcBillAdjustFee omcBillAdjustFee = new OmcBillAdjustFee();
        omcBillAdjustFee.setBillId(omcOldManBill.getId());
        omcBillAdjustFee.setAfterAdjustBalance(afterAdjustBalance);
        omcBillAdjustFee.setBeforeAdjustBalance(beforeAdjustBalance);
        omcBillAdjustFee.setPayableFeeBalance(omcReviseQuery.getAgio());
        omcBillAdjustFee.setLeaveBackFee(omcReviseQuery.getLeaveFee());
        omcBillAdjustFee.setMealBackFee(omcReviseQuery.getPackFee());
        omcBillAdjustFee.setGroupId(omcReviseQuery.getGroupId());
        omcBillAdjustFee.setTotalFee(totalFee);
        omcBillAdjustFee.setUpdateInfo(loginAuthDto);
        omcBillAdjustFeeMapper.insertSelective(omcBillAdjustFee);

        // 账单调整入库
        // 清除周期收费项
        OmcCycleExpenseItem omcCycleExpenseItem = new OmcCycleExpenseItem();
        omcCycleExpenseItem.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);
        omcCycleExpenseItem.setIsAdjust(Constant.EXPENSE_TYPE_MODEL_CODE_ADJUST);   // 删除可调整的
        omcCycleExpenseItem.setOldmanId((long) omcReviseQuery.getOldmanId());

        omcCycleExpenseItemMapper.delete(omcCycleExpenseItem);
        omcCycleExpenseItemService.batchSave(omcCycleExpenseItemList);

        // 账单Id
        omcRevise.setBillId(omcOldManBill.getId());

        omcOldmanStatusService.oldmanReviseEnd(omcReviseQuery.getOldmanId());

        return omcReviseMapper.updateByPrimaryKeySelective(omcRevise);
    }

    @Test
    public void calc() {
        // 消费合计
        BigDecimal total = new BigDecimal(-360);
        // 调整余额
        BigDecimal beforeAdjustBalance = new BigDecimal(-2628);
        // 实际合缴费用 total_fee
        BigDecimal totalFee;

        BigDecimal afterAdjustBalance = beforeAdjustBalance.subtract(total);
        int r = afterAdjustBalance.compareTo(BigDecimal.ZERO);
        if (r >= 0) {
            totalFee = BigDecimal.ZERO;
        } else {
            afterAdjustBalance = BigDecimal.ZERO;
            totalFee = total.multiply(new BigDecimal(-1));
        }

        System.out.println("afterAdjustBalance = " + afterAdjustBalance);
        System.out.println("totalFee = " + totalFee);
    }

    /**
     * query cur task states
     *
     * @param loginAuthDto
     *
     * @return
     */
    @Override
    public List<Integer> queryCurTaskStates(LoginAuthDto loginAuthDto) {

        List<Integer> states = Lists.newArrayList();

        Map<String, Object> reviseVarMap = omcReviseVarService
                .queryVarByGroupId(loginAuthDto.getGroupId());

        // 获取当前用户角色
        List<RpcRoleVo> roleVoList = uacRpcService.queryRoleListByUserId(loginAuthDto.getUserId());
        for (RpcRoleVo r : roleVoList) {
            if (reviseVarMap.get(ReviseConstant.REVISE_VAR_SERVICE).toString().contains(r.getRoleCode())) {
                // 服务部长角色（服务部长） ===> 查看提交申请的任务
                states.add(ReviseConstant.REVISE_STATE_APPLY);
            }
            if (reviseVarMap.get(ReviseConstant.REVISE_VAR_ADMIT).toString().contains(r.getRoleCode())) {
                // 接待角色（接待员、接待部长、评估员） ===> 查看服务部长确认的任务
                states.add(ReviseConstant.REVISE_STATE_SERVICE_AGREE);
            }
            if (reviseVarMap.get(ReviseConstant.REVISE_VAR_CHARGE).toString().contains(r.getRoleCode())) {
                // 收费员角色（收费员） ===> 查看服务部长确认的任务
                states.add(ReviseConstant.REVISE_STATE_ADMIT_CONFIRM);
            }
        }

        return states;
    }

    /**
     * 根据账单Id查询调房调级信息
     *
     * @param billId 账单Id
     * @return the revise vo
     */
    @Override
    public ReviseVo queryByBillId(Long billId) {

        OmcRevise omcRevise = new OmcRevise();
        omcRevise.setBillId(billId);
        omcRevise = omcReviseMapper.selectOne(omcRevise);
        if (omcRevise == null) {
            return null;
        }

        return queryById(omcRevise.getId());
    }

    public OmcCycleExpenseItem getOmcCycleExpenseItem(ReviseItemVo reviseItemVo) {

        OmcCycleExpenseItem omcCycleExpenseItem = new OmcCycleExpenseItem();
//        omcCycleExpenseItem.setActualFee(reviseItemVo.getActualFee());
//        omcCycleExpenseItem.setAmount(reviseItemVo.getAmount());
//        omcCycleExpenseItem.setCode(reviseItemVo.getCode());
//        omcCycleExpenseItem.setCostType(reviseItemVo.getCostType());
//        omcCycleExpenseItem.setExpenseItemId(reviseItemVo.getExpenseItemId());
//        omcCycleExpenseItem.setExpenseTypeId(reviseItemVo.getExpenseTypeId());
//        omcCycleExpenseItem.setItemType(reviseItemVo.getItemType());
//        omcCycleExpenseItem.setItemFee(reviseItemVo.getItemFee());
//        omcCycleExpenseItem.setItemName(reviseItemVo.getItemName());
//        omcCycleExpenseItem.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);
//        omcCycleExpenseItem.setResidueDegree(reviseItemVo.getResidueDegree());
//        omcCycleExpenseItem.setUserRateRefief(reviseItemVo.getUserRateRefief());
//        omcCycleExpenseItem.setUserTypeRateRefief(reviseItemVo.getUserTypeRateRefief());

        BeanUtils.copyProperties(reviseItemVo, omcCycleExpenseItem);
        omcCycleExpenseItem.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);

        return omcCycleExpenseItem;
    }

    public OmcOldManBill getOmcOldManBillByRevise(OmcRevise omcRevise) {

        OmcOldManBill omcOldManBill = new OmcOldManBill();

        Oldman oldman = new Oldman();
        oldman.setOldmanId(omcRevise.getOldmanId());
        Oldman old = oldmanService.selectByOld(oldman);

        OmcOldManSupplement omcOldManSupplement = new OmcOldManSupplement();
        omcOldManSupplement.setOldManId(omcRevise.getOldmanId().longValue());
        List<OmcOldManSupplement> select = supplementService.select(omcOldManSupplement);


        if (PublicUtil.isNotEmpty(select)){
            if (PublicUtil.isNotEmpty(select.get(0).getInDate())){
                omcOldManBill.setInDate(select.get(0).getInDate());
            }
        }
        omcOldManBill.setBillNumber(com.csun.cmny.provider.utils.DateUtil
                .getPayNumber(omcRevise.getGroupId()));
        omcOldManBill.setOldManId((long) omcRevise.getOldmanId());
        omcOldManBill.setGroupId(omcRevise.getGroupId());
        omcOldManBill.setIsPay(1);
        omcOldManBill.setTotalPay(omcRevise.getTotal());
        omcOldManBill.setPayTime(new Date());
        omcOldManBill.setBillType(3);
        omcOldManBill.setOldManName(old.getOldName());

        return omcOldManBill;
    }

    public OmcBillItem getOmcBillItemByRevise(ReviseItemVo reviseItemVo) {

        OmcBillItem omcBillItem = new OmcBillItem();

        // 可以调整的都是周期缴费
        omcBillItem.setModelCode(Constant.EXPENSE_TYPE_MODEL_CODE_CYCLE);
        omcBillItem.setActualFee(reviseItemVo.getActualFee());
        omcBillItem.setAdjustOrder(reviseItemVo.getAdjustOrder());
        omcBillItem.setAmount(reviseItemVo.getAmount());
        omcBillItem.setCostType(reviseItemVo.getCostType());
        omcBillItem.setExpenseItemId(reviseItemVo.getExpenseItemId());
        omcBillItem.setExpenseTypeId(reviseItemVo.getExpenseTypeId());
        omcBillItem.setIsAdjust(1);
        omcBillItem.setItemName(reviseItemVo.getItemName());
        omcBillItem.setItemType(reviseItemVo.getItemType());
        omcBillItem.setItemFee(reviseItemVo.getItemFee());
        omcBillItem.setItemType(reviseItemVo.getItemType());
        omcBillItem.setUserRateRefief(reviseItemVo.getUserRateRefief());
        omcBillItem.setUserTypeRateRefief(reviseItemVo.getUserTypeRateRefief());

        return omcBillItem;
    }
}
